package com.samp.solr.hanlp.utils;

import com.hankcs.hanlp.HanLP;
import com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLSentence;
import com.hankcs.hanlp.corpus.dependency.CoNll.CoNLLWord;
import com.hankcs.hanlp.dependency.IDependencyParser;
import com.hankcs.hanlp.dependency.nnparser.NeuralNetworkDependencyParser;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import com.samp.util.CnCharUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 通过名法分析，找出当前话语前后语句中最有可能的语句。
 */
public class SpeakExtract2 {

    private static Segment segment = HanLP.newSegment().enableAllNamedEntityRecognize(true);

    private static IDependencyParser parser = new NeuralNetworkDependencyParser().enableDeprelTranslator(false);

    private static Set<String> endSentenceChar = new HashSet<>();

    static {
        endSentenceChar.add("。");
        endSentenceChar.add("？");
        endSentenceChar.add("！");
    }

    private static List<String> getSentence(String msg){
        List<String> resultList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        boolean hasBegin = false;
        for( int i = 0 ; i < msg.length() ; i++ ){
            String currentChar = String.valueOf(msg.charAt(i));
            if( "“".equals(currentChar) ){
                //如果前面一个词是中文，则当前引号不是讲话。
                if( i > 1 && ! CnCharUtils.isChinese(msg.charAt(i-1)) ) {
                    hasBegin = true;
                    if (sb.length() > 0) {
                        resultList.add(sb.toString());
                        sb.setLength(0);
                    }
                }
            }
            if( hasBegin ){
                sb.append(currentChar);
                if( "”".equals(currentChar) ){
                    hasBegin = false;
                    if( sb.length() > 0 ){
                        resultList.add(sb.toString());
                        sb.setLength(0);
                    }
                }
            }else {
                sb.append(currentChar);
                if (endSentenceChar.contains(currentChar)) {
                    resultList.add(sb.toString());
                    sb.setLength(0);
                }
            }
        }
        if( sb.length() > 0 ){
            resultList.add(sb.toString());
        }
        return resultList;
    }

    /**
     * 判断是否为讲话，判断标准：
     * 以“开关，以”结束。
     * @param sentence
     * @return
     */
    private static boolean isSpeakSentence(String sentence){
        if( sentence.startsWith("“") && sentence.endsWith("”") ){
            return true;
        }
        return false;
    }

    /**
     * 找出当前讲话中，包含演讲者的句子。查找逻辑：先前再后
     * 1：前面一句为讲话，继续往前找，不为讲话，如果以句号等结尾，则不是，再判断是否有讲话的动作，有就标记。
     * 2：后面一名为讲话，继续往后找，不为讲话，如果有讲话的动作，并以句号结尾，则标记。
     *
     * @param sentenceList
     * @param i
     * @return
     */
    private static String getSpeakManSentence(List<String> sentenceList, Integer i){
        String previousSentence = null;
        if( i > 1 ){
            int previousIndex = i-1;
            previousSentence = sentenceList.get(previousIndex);
            while (isSpeakSentence(previousSentence) && i > 0){
                previousSentence = sentenceList.get(--previousIndex);
            }
            if( isSpeakSentence(previousSentence) ){
                previousSentence = null;
            }
            if( previousSentence != null ){
                String endChar = String.valueOf(previousSentence.charAt(previousSentence.length()-1));
                if( endSentenceChar.contains(endChar) ){
                    previousSentence = null;
                }
            }
            if( previousSentence != null && !getPerviousSpeakMan(previousSentence) ){
                previousSentence = null;
            }
        }
        if( previousSentence != null ){
            return previousSentence;
        }
        //上句没有，判断下句
        int nextIndex = i+1;
        String nextSentence = sentenceList.get(nextIndex);
        while (isSpeakSentence(nextSentence) && i < sentenceList.size()-1){
            nextSentence = sentenceList.get(++nextIndex);
        }
        if( isSpeakSentence(nextSentence) ){
            nextSentence = null;
        }
        if( nextSentence != null && !getPerviousSpeakMan(nextSentence)){
            nextSentence = null;
        }
        if( nextSentence != null ){
            return nextSentence;
        }
        return "not found";
    }

    public static String getSpeakPersonPervious(List<Term> termList, int i){
        if( i <= 0 ){
            return null;
        }
        Set<String> nameSet = new HashSet<>();
        nameSet.add("nrf");
        nameSet.add("nr");
        String sepakMan = null;
        boolean hasSpeakAction = false;
        for( ; i >= 0 ; i-- ){
            Term term = termList.get(i);
            if( SpeakExtract.isSpeakActionWord(term) ){
                hasSpeakAction = true;
            }
            //如果是标点符号，但不是冒号，退出。
            if( "w".equals(term.nature.toString()) ){
//                if( !("：".equals(term.word) || ":".equals(term.word)) ){
//                    break;
//                }
            }
            if( nameSet.contains(term.nature.toString()) ){
                sepakMan = term.word;
            }
            if( hasSpeakAction && sepakMan != null ){
                break;
            }
        }
        return sepakMan;
    }

    private static boolean getPerviousSpeakMan(String sentence){
        List<Term> termList = segment.seg(sentence);
        String speakMan = getSpeakPersonPervious(termList, termList.size()-1);
        if( speakMan != null ){
            return true;
        }else {
            return false;
        }
    }

    private static String findSpeakMan(String msg){
        if(StringUtils.isBlank(msg) ){
            return "no found.";
        }
        Set<String> nameSet = new HashSet<>();
        nameSet.add("nrf");
        nameSet.add("nr");
        CoNLLSentence sentence = parser.parse(msg);
        CoNLLWord[] wordArray = sentence.getWordArray();
        String result = "no found";
        for (int i = wordArray.length - 1; i >= 0; i--)
        {
            CoNLLWord word = wordArray[i];
            boolean test = false;
            if( "SBV".equals(word.DEPREL) && !test){
                //如果当前词性为nr等，直接返回。
                if( nameSet.contains(word.POSTAG) ) {
                    result = word.LEMMA;
                    break;
                }
                //向前找，看能否找到nr等。
                Integer previousIndex = i - 1;
                while ( previousIndex >= 0 ){
                    CoNLLWord headWord = wordArray[previousIndex];
                    if( nameSet.contains(headWord.POSTAG) ){
                        result = headWord.LEMMA;
                        break;
                    }
                    //如果碰到标点符号，则路过。
                    if( "w".equals(headWord.POSTAG) ){
                        break;
                    }
                    previousIndex--;
                }
                if( !"no found".equals(result) ){
                    break;
                }

            }
            //word.POSTAG 词性(细粒度,CPOSTAG为粗粒度)
            //word.NAME 等效字符串
            //
//            System.out.printf("%s --(%s)--> %s\n", word.CPOSTAG, word.NAME, word.POSTAG);
            if( test ) {
                System.out.printf("%s --(%s)--> %s\n", word.LEMMA, word.DEPREL, word.HEAD.LEMMA);
            }
        }
        return result+"("+msg+")";
    }

    private static void speakExtract(String msg){
        List<String> sentenceList = getSentence(msg);
        for(int i = 0 ; i < sentenceList.size() ; i++){
            String sentence = sentenceList.get(i);
//            System.out.println(sentence);
            if( isSpeakSentence( sentence ) ){
                //找出包含speakMan的语句。
                String speakSentence = getSpeakManSentence(sentenceList, i);
                String speakMan = findSpeakMan(speakSentence);
                System.out.println("---"+speakMan);
                System.out.println(sentence);
            }
        }
    }

    public static void main(String[] args) {
        try {
            String rawDoc = SpeakExtract.rawDoc;
            speakExtract(rawDoc);
//            List<String> list = new ArrayList<>();
//            list.add("华盛顿州副州长Cyrus Habib热情欢迎了王东华总领事一行，他对中美企业在华盛顿州展开合作充满期待");
//            //需要把Cyrus Habib换成中文才能识别。
//            for( String str: list ){
//                String speamMan = findSpeakMan(str);
//                System.out.println(str+"=====>"+speamMan);
//            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}
